/**
* Class.js
* 
* @author Demis Bellot
* @version 1.0
* 
* Copyright 2009, Demis Bellot
* http://code.google.com/p/ajaxstack/
*/

if (typeof Object.create !== 'function') {
    Object.create = function(o) {
        function F() { }
        F.prototype = o;
        return new F();
    };
}

function Class() { }
Class.typeMap = {};
Class.$type = "AjaxStack.Class";
Class.getType = function() { return this.$type; }
Class.getTypeClassName = function()
{
	var parts = this.$type.split('.');
	return parts[parts.length - 1];
}
Class.prototype.getType = function()
{
	return this.constructor.$type;
}
Class.prototype.getTypeClassName = function()
{
	return this.constructor.getTypeClassName();
}
Class.mapAdd = function(array, key)
{
	array.push(key);
	array[key] = true;
	return array;
}
Class.registerType = function(type, ctor)
{
	if (!type) return;
	Class.typeMap[type] = ctor;
	var nsTypes = type.split('.'), ns = window, nsType;
	for (var i = 0; i < nsTypes.length; i++)
	{
		var nsType = nsTypes[i];
		if (!ns[nsType]) ns[nsType] = i < nsTypes.length - 1 ? {} : ctor;
		ns = ns[nsType];
	}
}
Class.prototype.getBaseTypes = function(types)
{
	var base = this, types = types || [];
	do {
		base = base.constructor.$base;
		if (base) Class.mapAdd(types, base.getType());
	} while (base);
	return types;
}
Class.prototype.getBaseTypesAndSelf = function()
{
	return this.getBaseTypes(Class.mapAdd([], this.getType()));
}
Class.prototype.isTypeOf = function(typeName)
{
	return this.getBaseTypesAndSelf()[typeName] ? true : false;
}
Class.getConstructor = function(typeName)
{
	return Class.typeMap[typeName];
}
Class.create = function(typeName, ctorArgs)
{
	var ctor = Class.typeMap[typeName];
	function F() {
		ctor.apply(this, ctorArgs);
	}
	F.prototype = ctor.prototype;
	return new F();
}
Class.inherit = function(subClass, baseClass)
{
	function F() { }
	F.prototype = baseClass.prototype;
	subClass.$base = baseClass.prototype;
	subClass.$baseConstructor = baseClass;
	subClass.prototype = new F();
	subClass.prototype.constructor = subClass;
}
Function.prototype.extend = function(a, options, members)
{
	Class.inherit(this, a);
	options = options || {};
	Class.registerType(options.type, this);
	this.$type = options.type || Class.$type;
	this.getType = Class.getType;

	if (members)
	{
		if (typeof (members) === 'function')
			members(this.prototype);
		else
			for (var a in members) this.prototype[a] = members[a];
	}

	return this.prototype;
};

var is = {
	Null: function(a)
	{
		return a === null;
	},
	Undefined: function(a)
	{
		return a === undefined;
	},
	Empty: function(a)
	{
		return (a === null || a === undefined || a === "");
	},
	Function: function(a)
	{
		return (typeof (a) === 'function') ? a.constructor.toString().match(/Function/) !== null : false;
	},
	String: function(a)
	{
		if (a === null || a === undefined || a.type) return false;
		return (typeof (a) === 'string') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/string/i) !== null : false;
	},
	Array: function(a)
	{
		if (is.Empty(a) || a.type) return false;
		return (typeof (a) === 'object') ? a.constructor.toString().match(/array/i) !== null || a.length !== undefined : false;
	},
	Boolean: function(a)
	{
		if (is.Empty(a) || a.type) return false;
		return (typeof (a) === 'boolean') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/boolean/i) !== null : false;
	},
	Date: function(a)
	{
		if (is.Empty(a) || a.type) return false;
		return (typeof (a) === 'date') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/date/i) !== null : false;
	},
	Number: function(a)
	{
		if (is.Empty(a) || a.type) return false;
		return (typeof (a) === 'number') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/Number/) !== null : false;
	},
	Numeric: function(a)
	{
		return (a - 0) == a && a.length > 0;
	},
	Digit: function(a)
	{
		if (is.Empty(a)) return false;
		var s = a.toString();
		return (s.length == 1 && (s >= "0") && (s <= "9"));
	},
	Integer: function(a)
	{
		if (is.Empty(a)) return false;
		var s = a.toString();
		if (s[0] == '-') s = s.substr(1);
		for (i = 0, len = s.length; i < len; i++)
			if (!(s.charAt(i) >= "0" && s.charAt(i) <= "9")) return false;
		return true;
	},
	UnsignedInteger: function(a)
	{
		return is.isInteger(a) && parseInt(a) >= 0;
	},
	IntegerInRange: function(a, min, max)
	{
		if (!is.Integer(a)) return false;
		var val = parseInt(a);
		return val >= min && val <= max;
	},
	Object: function(a)
	{
		return (typeof (a) === 'object') ? a.constructor.toString().match(/object/i) !== null : false;
	},
	RegExp: function(a)
	{
		return (typeof (a) === 'function') ? a.constructor.toString().match(/regexp/i) !== null : false;
	},
	ValueType: function(a)
	{
		if (is.Empty(a) || a.type) return false;
		return is.String(a) || is.Date(a) || is.Number(a) || is.Boolean(a);
	},
	Class: function(a)
	{
		if (is.Empty(a)) return false;
		return a.constructor && a.constructor.$type ? true : false;
	},
	TypeOf: function(a, type)
	{
		return is.Class(a) && a.isTypeOf(type) ? true : false;
	}
};